﻿/**************************************************************************************
 * CrmDotNetCodeMigrator
 * Tools to assist the Dynamics CRM developer when moving their code from
 * CRM 4.0 to CRM 2011.
 *
 * @copyright    Copyright (c) 2013, CRM Accelerators (http://www.crmaccelerators.net)
 * @license      Microsoft Public License (Ms-PL)
 * @developer    Mitch Milam (http://blogs.infinite-x.net)
 * @version      0.1
 *
 * THIS SOFTWARE IS PROVIDED BY CRM Accelerators ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL CRM Accelerators BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 **************************************************************************************/

#region

using System.Linq;
using Microsoft.Xrm.Client;
using Microsoft.Xrm.Client.Services;
using Microsoft.Xrm.Sdk.Messages;
using Microsoft.Xrm.Sdk.Metadata;

#endregion

namespace CrmDotNetCodeMigrator
{
    public class Crm2011
    {
        public string CrmServerUrl { get; set; }
        public string UserName { get; set; }
        public string Password { get; set; }
        public string DomainName { get; set; }
        public ConnectionTypes ConnectionType { get; set; }

        public EntityMetadata[] EntityMetadataAll { get; set; }
        public CrmEntityCollection EntityList { get; set; }
        public CrmAttributeCollection AttributeList { get; set; }
        public OrganizationService Service { get; set; }

        public Crm2011()
        {
            ConnectionType = ConnectionTypes.Testing;

            Service = GetCrmService();

            RetrieveEntityMetadata();

            EntityList = BuildEntityList();
        }

        public Crm2011(string crmServerUrl, string userName, string password, string domainName, ConnectionTypes connectionType)
        {
            CrmServerUrl = crmServerUrl;
            UserName = userName;
            Password = password;
            DomainName = domainName;
            ConnectionType = connectionType;

            Service = GetCrmService();

            RetrieveEntityMetadata();

            EntityList = BuildEntityList();
        }

        public OrganizationService GetCrmService()
        {
            return new OrganizationService(CrmConnection.Parse(BuildConnectionString()));
        }

        private string BuildConnectionString()
        {
            const string deviceId = "contoso-ba9f6b7b2e6d";
            const string devicePassword = "passcode";

            var connectionString = string.Empty;

            //
            // Connection strings for the various connection methods
            // documented in the CRM 2011 SDK.
            //
            // For more information visit:
            // http://technet.microsoft.com/en-us/library/gg695810.aspx
            //
            switch (ConnectionType)
            {
                case ConnectionTypes.Testing:
                    CrmServerUrl = "http://crm2011/contoso";
                    UserName = "administrator";
                    Password = "pass@word1";
                    DomainName = "contoso";

                    connectionString = string.Format("Url={0}; Domain={1}; Username={2}; Password={3}", 
                                                     CrmServerUrl, DomainName, UserName, Password);
                    break;
                case ConnectionTypes.ActiveDirectory:
                    connectionString = string.Format("Url={0}; Domain={1}; Username={2}; Password={3}", 
                                                     CrmServerUrl, DomainName, UserName, Password);
                    break;
                case ConnectionTypes.ActiveDirectoryIntegrated:
                    connectionString = string.Format("Url={0};", CrmServerUrl);
                    break;
                case ConnectionTypes.Online:
                    connectionString = string.Format("Url={0}; Username={1}; Password={2}; DeviceID={3}; DevicePassword={4}", 
                                                     CrmServerUrl, UserName, Password, deviceId, devicePassword);
                    break;
                case ConnectionTypes.OnlineOffice365:
                    connectionString = string.Format("Url={0}; Username={1}; Password={2};", 
                                                      CrmServerUrl, UserName, Password);
                    break;
            }

            return connectionString;
        }

        public void RetrieveEntityMetadata()
        {
            var request = new RetrieveAllEntitiesRequest
                {
                    EntityFilters = EntityFilters.All,
                    RetrieveAsIfPublished = true
                };

            var response = (RetrieveAllEntitiesResponse)Service.Execute(request);

            if (response != null)
            {
                EntityMetadataAll = response.EntityMetadata;
            }
        }

        public CrmEntityCollection BuildEntityList()
        {
            var collection = new CrmEntityCollection();

            collection.AddRange(
                (from entity in
                     EntityMetadataAll.Where(
                         entity => entity.IsCustomizable.Value)
                 orderby entity.LogicalName
                 select
                     new CrmEntity
                     {
                         SchemaName = entity.SchemaName,
                         LogicalName = entity.LogicalName,
                     }).ToList()
                     );

            return collection;
        }

        public CrmAttributeCollection BuildAttributeList(string entityLogicalName)
        {
            var collection = new CrmAttributeCollection();

            var request = new RetrieveEntityRequest
                      {
                          RetrieveAsIfPublished = true,
                          LogicalName = entityLogicalName,
                          EntityFilters = EntityFilters.Attributes
                      };

            var response = (RetrieveEntityResponse)Service.Execute(request);

            if (response != null &&
                response.EntityMetadata == null)
            {
                return collection;
            }

            collection.AddRange(from attribute in response.EntityMetadata.Attributes
                                where attribute.IsValidForUpdate != null &&
                                (attribute.IsValidForCreate != null &&
                                ((attribute.AttributeOf == null) &&
                                (!attribute.LogicalName.EndsWith("_base")) &&
                                attribute.IsValidForCreate.Value &&
                                attribute.IsValidForUpdate.Value))
                                orderby attribute.LogicalName
                                select new CrmAttribute
                                    {
                                        EntityLogicalName = entityLogicalName,
                                        LogicalName = attribute.LogicalName,
                                        SchemaName = attribute.SchemaName,
                                    });

            return collection;
        }
    }
}